//raycasting object for Gamelib by Robert Gamble (robert@thebluefishcompany.com)
//this is a first release and was done during 1 lunch break so expect bugs!

//some features in the renderer are not yet implemented (textures, etc) sorry!
//see the htm file included with this to see how to use it.

function rc_setcontrols(up,down,left,right)
{
	//sets the controls.
	this.upkey=Kb_trapkey(up);			
	this.downkey=Kb_trapkey(down);			
	this.leftkey=Kb_trapkey(left);
	this.rightkey=Kb_trapkey(right); 
}

function rc_settextures(txt)
{
	//loads textures into an array.
	i=0;
	while(i<txt.length)
	{
		this.texture[i]=new Image();
		this.texture[i].src=txt[i];
		i++;
	}
}

function rc_renderproperties(_textures,_fog,_drawdist,_blur)
{
	//sets the renderer properties
	with(this.renderer)
	{
		textures=_textures;
		fog=_fog;
		drawdist=_drawdist;
		blur=_blur;
	}
}

function rc_map(_h,_w,dat)
{
	//load the map properties
	with(this.map)
	{
		h=_h;
		w=_w;
		data=dat;
	}
}

function rc_setspeed(rot,mov)
{
	this.mov=mov;
	this.rot=rot;
}

function rc_rad(ang)
{
	return ang*((22/7)/180);
}

function rc_peek(x,y)
{
	return this.map.data[(this.map.w*parseInt(y))+parseInt(x)];
}

function rc_controls()
{
	press=false;
	if(this.downkey.pressed)	
	{
		 tempX=this.player.x-(this.lookups.sin[this.player.angle]*this.mov)
		 tempY=this.player.y-(this.lookups.cos[this.player.angle]*this.mov)
		 if(this.peek(tempX>>this.shft ,tempY>>this.shft)==0 ){this.player.x = tempX; this.player.y = tempY;press=true}
	}
	else if(this.upkey.pressed)
	{
		 tempX=this.player.x+(this.lookups.sin[this.player.angle]*this.mov)
		 tempY=this.player.y+(this.lookups.cos[this.player.angle]*this.mov)
		 if(this.peek(tempX>>this.shft,tempY>>this.shft)==0 ){this.player.x = tempX; this.player.y = tempY;press=true}
	}
	
	if(this.leftkey.pressed){this.player.angle-=this.rot;press=true}
	else if(this.rightkey.pressed){this.player.angle+=this.rot;press=true}

	if(this.player.angle>359)this.player.angle-=360;
	else if(this.player.angle<0)this.player.angle+=360;

	return press;
}

function rc_cast()
{
  i=0;
  a=this.player.angle-110;
  str="";
  
  tpy=Math.floor(this.player.y>>this.shft)<<(this.shft)
  tpx=Math.floor(this.player.x>>this.shft)<<(this.shft)
  
  while(true)//i<player.viewport)
  {
   if(a>=360)a-=360;
   if(a<0)a+=360;

   str+=this.rend(a,i,tpx,tpy)
   i+=1;
   a+=1;
   if(i>=40)break;
  }

  this.screen.write(str);
}

function rc_raycast(ang,x,px,py)
{
 tann=this.lookups.tan[ang]

 this.ray.y=(ang<180)?py-1:py+this.scale;
 ya=(ang<180)?-this.scale:this.scale;

 this.ray.x = this.player.x + (this.player.y-this.ray.y)/tann;
 xa=Math.floor(this.scale/tann);
 xa=(ang>180)?xa=-xa:xa=+xa;
   
 this.ray.vx=(ang>270 || ang<90)?px+ this.scale:px  - 1;
 vxa=(ang>270 || ang<90)?this.scale:-this.scale;

 this.ray.vy =this.player.y + (this.player.x-this.ray.vx)*tann;
 vya=this.scale*tann;		
 
 if(ang>270 || ang<90)vya=-vya;
 if(ang==0 || ang ==180)vya=0;
 
 tmp1=0
 tmp2=0
 col1=false;
 col2=false;
 tmp="";

 while(true){
 
 while(true)
 {
  col1=this.peek(this.lookups.pos[Math.round(this.ray.x)],this.lookups.pos[Math.round(this.ray.y)])
  if(col1!=false)
    {
	tmp1=Math.abs(this.ray.x - this.player.x) * Math.abs(this.lookups.cos[ang]) + Math.abs(this.ray.y - this.player.y) * Math.abs(this.lookups.sin[ang])	 
	 break;
    }
 else{
  this.ray.x+=xa;
  this.ray.y+=ya; 
 }
 }

 while(true)
 {
 col2=this.peek(this.lookups.pos[Math.round(this.ray.vx)],this.lookups.pos[Math.round(this.ray.vy)])
 if(col2!=false)
    {
      	tmp2=Math.abs(this.ray.vx - this.player.x) * Math.abs(this.lookups.cos[ang]) + Math.abs(this.ray.vy - this.player.y) * Math.abs(this.lookups.sin[ang])
		 break;
      }
   else{
  this.ray.vx+=vxa;
  this.ray.vy+=vya;
   }
 }	
 
 if(tmp1<=tmp2)
  {
	//see if ray has strayed out of bounds
    if(col1==undefined)break;
    else{
		this.ray.x+=xa;
		this.ray.y+=ya;
		}

   this.ray.length=this.lookups.height[Math.round(tmp1)];
   hgt=col1;
  
   shd="aaaaaa"
  }
 
 else
  {
   if(col2==undefined)break;
   else{
	  this.ray.vx+=vxa;
	  this.ray.vy+=vya;
	  }

   this.ray.length=this.lookups.height[Math.round(tmp2)];
   hgt=col2;
 
   shd="555555"
  }


 walltop=(this.ray.length>>1) 

 
  xpos=(x<<3)

  xtop=100-walltop


  height=this.ray.length/hgt


  xtop+=(this.ray.length-height)


  dist=this.ray.length+this.renderer.drawdist
 
	strtmp=""
	
	if(dist>10){		
		if(hgt>1) //check if a floor needs to be drawn
		{
			ftop=(100+(100/hgt)); //work out top of the floor

			//draw the floor
				if(ftop<=xtop)
				{
					strtmp+="<div style='position:absolute;top:"+(ftop)+";left:"+(xpos)+";width:8;height:"+(height)+";overflow:hidden;background-color:cccccc'>";
    				strtmp+="</div>";
				}
			}
	    strtmp+="<div style='position:absolute;top:"+(xtop)+";left:"+(xpos)+";width:8;height:"+(height)+";overflow:hidden;background-color:"+shd+"'>";
    	strtmp+="</div>";		   		
		tmp=strtmp+tmp;
    	} 
	else break;

	if(hgt<=1)break;	  //if this wall slice is hiding the walls behind it don't bother rendering them
	}
	
  return tmp	
}

function maze()
{
	//define variables
	this.upkey=false,this.downkey=false,this.leftkey=false,this.rightkey=false;
	this.texture=new Array();
	this.scale=64;
	this.shft=6;
	this.mov=10;
	this.rot=10;
	this.renderer=new Object();
	this.renderer.textures=false;
	this.renderer.fog=false;
	this.renderer.drawdist=false;
	this.renderer.blur=false;

	this.map=new Object();
	this.map.h=false;
	this.map.w=false;
	this.map.data=false;

	this.player=new Object();
	this.player.x=1*this.scale;
	this.player.y=1*this.scale;
	this.player.angle=20;

	this.lookups=new Object();
	this.lookups.sin=new Array();
	this.lookups.cos=new Array();
	this.lookups.tan=new Array();
	this.lookups.height=new Array();
	this.lookups.pos=new Array();

	i=0;
	while(i<=360)
	{
		this.lookups.sin[i]=Math.sin(rc_rad(i));
		this.lookups.cos[i]=Math.cos(rc_rad(i));
		this.lookups.tan[i]=Math.tan(rc_rad(i));
		i++;
	}

	z=10000;
	do{
		this.lookups.height[z]=Math.round(64/z*227);	 
		this.lookups.pos[z]=z/64
		z--;
		}while(z>=0)

	this.ray=new Object();
	this.ray.x=0;
	this.ray.y=0;
	this.ray.vx=0;
	this.ray.vy=0;		  
	this.ray.length=0;
	
	//functions
	this.setcontrols=rc_setcontrols;
	this.setmap=rc_map;
	this.setspeed=rc_setspeed;
	this.setrenderer=rc_renderproperties;
    this.textures=rc_settextures;
	
	this.controls=rc_controls;
	this.cast=rc_cast;
	
	this.peek=rc_peek;
	this.rend=rc_raycast;


	this.screen=new Gl_layer(10,10,400,'');

	this.screen.resizeTo(400,600);
}